﻿using System;
using System.Collections.Generic;
using System.Data;
using System.Text;
using System.Diagnostics;
using DslModeling=global::Microsoft.VisualStudio.Modeling;
using DslDiagrams=global::Microsoft.VisualStudio.Modeling.Diagrams;
using DslValidation=global::Microsoft.VisualStudio.Modeling.Validation;

namespace Salamanca.Sdml
{
    [DslValidation.ValidationState(DslValidation.ValidationState.Enabled)]
    partial class Association:
        IDataTableHolder
    {
        partial class FormPropertyHandler
        {
            protected override void OnValueChanged(Association element, AssociationForm oldValue, AssociationForm newValue)
            {
                base.OnValueChanged(element, oldValue, newValue);

                switch (newValue)
                {
                case AssociationForm.Aggregation:
                    if (!IsSingleMultiplicity(element.SourceMultiplicity))
                        element.SourceMultiplicity=Multiplicity.ZeroOne;
                    break;
                case AssociationForm.Composition:
                    if (element.SourceMultiplicity!=Multiplicity.One)
                        element.SourceMultiplicity=Multiplicity.One;
                    break;
                }
            }
        }

        public string GetSourceRoleName()
        {
            return string.IsNullOrEmpty(SourceRoleName) ? (IsSingleMultiplicity(SourceMultiplicity) ? Source.Name : Source.GetPluralName()) : SourceRoleName;
        }

        public string GetTargetRoleName()
        {
            return string.IsNullOrEmpty(TargetRoleName) ? (IsSingleMultiplicity(TargetMultiplicity) ? Target.Name : Target.GetPluralName()) : TargetRoleName;
        }

        [DslValidation.ValidationMethod(DslValidation.ValidationCategories.Menu | DslValidation.ValidationCategories.Open | DslValidation.ValidationCategories.Save)]
        private void ValidateCardinality(DslValidation.ValidationContext context)
        {
            switch (this.Form)
            {
            case AssociationForm.Aggregation:
                if (!IsSingleMultiplicity(this.SourceMultiplicity))
                    context.LogError(Resources.SR.AggregationSourceMultiplicityMustBeSingle, "SDML02", this);
                break;
            case AssociationForm.Composition:
                if (this.SourceMultiplicity!=Multiplicity.One)
                    context.LogError(Resources.SR.CompositionSourceMultiplicityMustBeOne, "SDML02", this);
                break;
            default:
                if (!IsSingleMultiplicity(this.SourceMultiplicity) && IsSingleMultiplicity(this.TargetMultiplicity))
                    context.LogError(Resources.SR.AssociationMultipleSingleMultiplicityMustBeReversed, "SDML02", this);
                break;
            }
            if ((this.SourceMultiplicity==Multiplicity.ZeroOne) && (this.TargetMultiplicity==Multiplicity.One))
                context.LogError(Resources.SR.AssociationOptionalToOneMultiplicityMustBeReversed, "SDML02", this);
        }

        public static bool IsSingleMultiplicity(Multiplicity multiplicity)
        {
            return (multiplicity==Multiplicity.One) || (multiplicity==Multiplicity.ZeroOne);
        }

        public static bool IsMandatoryMultiplicity(Multiplicity multiplicity)
        {
            return (multiplicity==Multiplicity.One) || (multiplicity==Multiplicity.OneMany);
        }

        public DataRelation DataRelation
        {
            get
            {
                Source.DomainModel.LoadDataSet();
                return _RelationReference!=null ? (DataRelation)_RelationReference.Target : null;
            }
            set
            {
                _RelationReference=new WeakReference(value);
            }
        }

        public DataTable DataTable
        {
            get
            {
                Source.DomainModel.LoadDataSet();
                return _TableReference!=null ? (DataTable)_TableReference.Target : null;
            }
            set
            {
                _TableReference=new WeakReference(value);
            }
        }

        private WeakReference _RelationReference;
        private WeakReference _TableReference;
    }

    partial class AssociationConnector
    {

        protected override void InitializeResources(DslDiagrams.StyleSet classStyleSet)
        {
            // First the generated behavior.
            base.InitializeResources(classStyleSet);

            // This will cause OnAssociatedPropertyChanged to be called when the user changes the Form value.
            AssociationConnector.AssociateValueWith(Store, Association.FormDomainPropertyId);
        }

        protected override void OnAssociatedPropertyChanged(DslDiagrams.PropertyChangedEventArgs e)
        {
            // This is called when any associated domain property is changed; so first find out which one.
            if ("Form".Equals(e.PropertyName))
            {
                Debug.Assert(e.NewValue is AssociationForm, "Wrong type of value for Association.Form");

                switch ((AssociationForm)e.NewValue)
                {
                case AssociationForm.Aggregation:
                    this.DecoratorTo=null;
                    this.DecoratorFrom=DslDiagrams.LinkDecorator.DecoratorEmptyDiamond;
                    break;
                case AssociationForm.BiDirectional:
                    this.DecoratorTo=null;
                    this.DecoratorFrom=null;
                    break;
                case AssociationForm.Composition:
                    this.DecoratorTo=null;
                    this.DecoratorFrom=DslDiagrams.LinkDecorator.DecoratorFilledDiamond;
                    break;
                case AssociationForm.UniDirectional:
                    this.DecoratorTo=DslDiagrams.LinkDecorator.DecoratorEmptyArrow;
                    this.DecoratorFrom=null;
                    break;
                default:
                    Debug.Fail("Unrecognized value for Association.Sort");
                    break;
                }
            }

            // Generated behavior - will redraw the shape.
            base.OnAssociatedPropertyChanged(e);
        }
    }
}
